<?php

namespace App\Models;

// use App\Jobs\BuyDone;

class Buy extends BaseModel
{
  protected $table = 'buy';
  public $incrementing = false;
  protected $keyType = 'string';
  protected $guarded = [];

  protected $casts = [
    'took_at' => 'datetime',
    'frozen_at' => 'datetime',
    'done_at' => 'datetime',
    'freeze_at' => 'datetime',
    'unfreeze_at' => 'datetime',
    'coins' => 'float',
    'deposit' => 'float',
    'fee' => 'float',
    'tip' => 'float',
    'seller_fee' => 'float',
    'seller_tip' => 'float',
    'callback_ok' => 'boolean',
    'callback_content' => 'array'
  ];

  public function scopeWhenSellerName($q, $name)
  {
    $q->when($name, function ($q) use ($name) {
      $q->whereHas('seller', function ($q) use ($name) {
        $q->where('username', $name);
      });
    });
  }

  public function scopeGroupSumForUser($q, $raw, $foreign_id)
  {
    $q->selectRaw($raw)
      ->whereColumn($foreign_id, 'users.id')
      ->where('state', '<>', 'fail')
      ->groupBy($foreign_id);
  }

  public function scopeState($q, $state)
  {
    $q->where('state', $state);
  }

  public function scopeDone($q)
  {
    $q->whereIn('state', ['unfreeze', 'fail']);
  }

  public function scopeUndone($q)
  {
    $q->whereNotIn('state', ['unfreeze', 'fail']);
  }

  public function member()
  {
    return $this->belongsTo(User::class, 'member_id');
  }

  public function agent()
  {
    return $this->belongsTo(User::class, 'agent_id');
  }

  public function seller()
  {
    return $this->BelongsTo(User::class, 'seller_id');
  }

  public function balances()
  {
    return $this->hasMany(Balance::class, 'order_id');
  }

  public function cancels()
  {
    return $this->hasMany(Cancel::class);
  }

  public function cancelLog()
  {
    return $this->cancels()->create([
      'buy_id' => $this->id,
      'member_id' => $this->member_id,
      'seller_id' => $this->seller_id,
      'coins' => $this->coins,
    ]);
  }

  public function unfreeze()
  {
    \DB::transaction(function () {
      $this->lockForUpdate();

      if ($this->state !== 'frozen') {
        fail('状态错误');
      }
      $this->state = 'unfreeze';
      $this->unfreeze_at = now();
      $this->save();

      // 用户买币、用户买币佣金、用户买币奖励
      $this->member->lockForUpdate();
      $this->member->coinsChange($this->coins, '用户买币', $this->id);
      $this->member->coinsChange($this->fee, '用户买币佣金', $this->id);
      $this->member->coinsChange($this->tip, '用户买币奖励', $this->id);

      if ($this->agent) {
        $this->agent->lockForUpdate();
        // 代理佣金、代理奖励
        $this->agent->coinsChange($this->agent_fee, '代理佣金', $this->id);
        $this->agent->coinsChange($this->agent_tip, '代理奖励', $this->id);
      }
    });
  }

  public function agentFee()
  {
    $agent = $this->member->parent;
    $diff = bcsub($agent->fee_ratio, $this->member->fee_ratio, 3);
    return bcmul($diff, $this->coins, 3);
  }

  public function agentTip()
  {
    $agent = $this->member->parent;
    return bcsub($agent->tip, $this->member->tip, 2);
  }

  public function callback()
  {
    if ($this->callback_ok || !$this->seller->notify_url || !$this->transaction_id) {
      return;
    }
    // \Log::debug('callback start: ' . json_encode($this->toArray()));
    $data = [
      'code' => 1,
      'message' => 'ok',
      'data' => $this->only(
        'id',
        "transaction_id",
        "bank",
        "bankcard",
        "realname",
        "coins",
        "seller_fee",
        "seller_tip",
        "state",
        "created_at"
      ),
      'sign' => md5($this->seller->code .  $this->seller->api_token . $this->transaction_id)
    ];
    try {
      $response = \Http::post(
        $this->seller->notify_url,
        $data
      );
    } catch (\Exception $e) {
      fail('发送失败');
    } finally {
      $this->increment('callback_num');
      $this->callback_content = $data;
      $this->save();
    }
    $text = $response->getBody()->getContents();
    \Log::debug('callback response: ' . $data['data']['id'] . json_encode($text));
    if ($text === 'ok') {
      $this->callback_ok = true;
      $this->save();
      return true;
    }
    return false;
  }

  public function clearMember()
  {
    $this->fee = null;
    $this->tip = null;
    $this->deposit = null;
    $this->agent_id = null;
    $this->agent_fee = null;
    $this->agent_tip = null;
    $this->agent_tip_fee = null;
    $this->freeze_at = null;
    $this->state = 'waiting';
    $this->took_at = null;
    $this->member_id = null;
    $this->save();
  }
}
